/*
我们可以自己手动将class文件加载到JVM中么？
先自己写一个Test类，使用javac编译成class文件后，放到根目录或同级目录（决定了使用类对象创建实例的时候的路径）
然后使用自己编写的MyClassLoader加载器把Test.class动态加载到JVM里面，调用里面的方法，修改字段的值。
为什么要自己编写ClassLoader，因为普通的ClassLoader无法加载二进制文件。
 */
package Class_Loader;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class My_ClassLoader {

    static class MyClassLoader extends ClassLoader{  //继承ClassLoader，重写defineClass方法，因为父类的defineClass是protected final方法
        public Class<?> defineClass(String name, byte[] b){  //重写defineClass方法，把class文件用FileInputStream读出来的byte[]数组，把byte数组加载到jvm中
            return defineClass(name, b, 0, b.length); //调用Protected方法，只是载入外部class文件
        }
    }

    public static void main(String[] args) throws IOException {
        MyClassLoader classLoader = new MyClassLoader();
        FileInputStream stream = new FileInputStream("src/Class_Loader/Test.class");  //把class文件读到stream流。相对路径的根路径是以项目路径为根目录的
        byte[] bytes = new byte[stream.available()];  //创建byte数字，大小是stream流的available
        stream.read(bytes);  //把流读到byte数组中
        Class<?> clazz =classLoader.defineClass("Class_Loader.Test", bytes); //通过自己定义的ClassLoader把byte数组加载到jvm，返回一个类对象。传入String name这里的类名必须与我们定义的保持一致
        System.out.println(clazz.getName()); //成功加载外部class文件
        //现在我们就将class文件读取并解析为Class了，就可以对此类就行操作了。此时和原来的Test.java没关系了，是从Test.class文件动态加载的
        //注意，我们无法直接在代码中使用此类型，因为它是我们动态加载的
        //试试创建一个类对象并调用其方法

        try{
            Object obj = clazz.newInstance();
            Method method = clazz.getMethod("test", String.class); //获取Test里定义的test(String str)方法
            Field field = clazz.getField("text");  //获取成员变量text字段
            field.set(obj, "华强：");  //给text赋值
            method.invoke(obj, "哥们这瓜多少钱一斤");  //调用方法，给方法传参
        }catch (Exception e){
            e.printStackTrace();
        }

        /*
        通过这种方式，我们就可以实现外部加载一个类，甚至网络加载一个类，只需要把文件传递即可。这样就无需将代码写在本地，而是动态进行传递，可以一定程度上防止破解(只是一定程度)
        而且在更多情况下，我们可以对byte[]进行加密，保证在传输过程中的安全性。
         */
    }
}
